import * as config from "config";
import {Types} from "mongoose";
import {InstanceType} from "typegoose";
import {Address} from "../../database/models/address";
import {GamePrizeModel} from "../../database/models/gamePrize";
import GM from "../../database/models/gm";
import {KickbackRecordModel} from "../../database/models/kickbackRecord";
import {PaymentOrderModel} from "../../database/models/paymentOrder";
import {Player} from "../../database/models/player";
import {Product} from "../../database/models/Product";
import {ProductOrder} from "../../database/models/ProductOrder";
import {wechatPayAuther} from "../../wechat/wechatCashier";
import {expect, requestToApiServer, setupTestEnv, tearDownTestEnv, XMLbuilder} from "./helper";

describe('直接购买', () => {

  let player: InstanceType<Player> = null
  let playerNoInvite: InstanceType<Player> = null
  let product: InstanceType<Product> = null
  let jwt: string = null
  let jwtNoInvite: string = null
  let address: InstanceType<Address> = null

  before(async () => {
    const env = await setupTestEnv()

    player = env.player
    playerNoInvite = env.playerNoInvite
    product = env.product
    jwt = env.jwt
    jwtNoInvite = env.jwtNoInvite
    address = env.address
  })

  after(() => {
    return tearDownTestEnv()
  })

  context('微信支付', () => {

    it('微信购买', () => {

      return requestToApiServer()
        .post(`/productorder/${product.id}`)
        .set({'x-jwt': jwt})
        .send({
          payType: 'wechatPay'
        })
        .expect(200)
    })

    it('有邀请人确认付款', async () => {

      let productOrder: InstanceType<ProductOrder> = null
      const gmBefo = await GM.findOne({role: `super`}).lean()
      const gm1Befo = await GM.findOne({role: `level1`}).lean()
      const gm2Befo = await GM.findOne({role: `level2`}).lean()

      await requestToApiServer()
        .post(`/productorder/${product.id}`)
        .set({'x-jwt': jwt})
        .send({
          payType: 'wechatPay'
        })
        .expect(200)
        .then(({body}) => {
          productOrder = body.data.productOrder
        })

      const payOrder = await PaymentOrderModel.findOne({
        orderType: 'ProductOrder', order: productOrder._id
      })

      const notification = {
        out_trade_no: payOrder.id,
        result_code: 'SUCCESS', return_code: 'SUCCESS',
      }
      const sign = wechatPayAuther.sign(notification)

      const xml = XMLbuilder.buildObject({...notification, sign})

      await requestToApiServer()
        .post('/wechatpay/notify')
        .type('xml')
        .send(xml)
        .expect(200)
        .then(res => {
          expect(res.text).to.equal('<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>')
        })

      expect(await PaymentOrderModel.findOne({
        orderType: 'ProductOrder', order: productOrder._id
      })).to.have.properties({state: 'finished'})

      expect(await GamePrizeModel.findOne({product: product._id}).lean())
        .to.have.properties({
        state: 'idle',
        from: 'buy',
        selectState: `notAllowed`
      })

      const RMBCost = payOrder.price
      const pKickback = config.get<number>('kickback.buy.playerToGmKickback')
      const gmKickback = config.get<number>('kickback.buy.gmToGmKickback')

      const gm = await GM.findOne({role: `super`}).lean()
      const gm1 = await GM.findOne({role: `level1`}).lean()
      const gm2 = await GM.findOne({role: `level2`}).lean()
      expect(gm2.cashKickback - gm2Befo.cashKickback).to.equal(RMBCost * pKickback)
      expect(gm1.cashKickback - gm1Befo.cashKickback).to.equal(RMBCost * pKickback * gmKickback)
      expect(gm.cashKickback - gmBefo.cashKickback).to.equal(RMBCost * pKickback * (1 + gmKickback))

      const kickbackRecord = await KickbackRecordModel.findOne({fromId: Types.ObjectId(productOrder._id)})
      expect(kickbackRecord.kickback2).to.equal(RMBCost * pKickback)
      expect(kickbackRecord.kickback1).to.equal(RMBCost * pKickback * gmKickback)
      expect(kickbackRecord.kickbackAll).to.equal(RMBCost * pKickback * (1 + gmKickback))
    })
    it('无邀请人确认付款', async () => {

      let productOrder: InstanceType<ProductOrder> = null
      const gmBefo = await GM.findOne({role: `super`}).lean()
      const gm1Befo = await GM.findOne({role: `level1`}).lean()
      const gm2Befo = await GM.findOne({role: `level2`}).lean()

      await requestToApiServer()
        .post(`/productorder/${product.id}`)
        .set({'x-jwt': jwtNoInvite})
        .send({
          payType: 'wechatPay'
        })
        .expect(200)
        .then(({body}) => {
          productOrder = body.data.productOrder
        })

      const payOrder = await PaymentOrderModel.findOne({
        orderType: 'ProductOrder', order: productOrder._id
      })

      const notification = {
        out_trade_no: payOrder.id,
        result_code: 'SUCCESS', return_code: 'SUCCESS',
      }
      const sign = wechatPayAuther.sign(notification)

      const xml = XMLbuilder.buildObject({...notification, sign})

      await requestToApiServer()
        .post('/wechatpay/notify')
        .type('xml')
        .send(xml)
        .expect(200)
        .then(res => {
          expect(res.text).to.equal('<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>')
        })

      expect(await PaymentOrderModel.findOne({
        orderType: 'ProductOrder', order: productOrder._id
      })).to.have.properties({state: 'finished'})

      expect(await GamePrizeModel.findOne({product: product._id}).lean())
        .to.have.properties({
        state: 'idle',
        from: 'buy',
        selectState: `notAllowed`
      })

      const gm = await GM.findOne({role: `super`}).lean()
      const gm1 = await GM.findOne({role: `level1`}).lean()
      const gm2 = await GM.findOne({role: `level2`}).lean()
      expect(gm2.cashKickback - gm2Befo.cashKickback).to.equal(0)
      expect(gm1.cashKickback - gm1Befo.cashKickback).to.equal(0)
      expect(gm.cashKickback - gmBefo.cashKickback).to.equal(0)

      const kickbackRecord = await KickbackRecordModel.findOne({fromId: Types.ObjectId(productOrder._id)})
      expect(kickbackRecord).to.equal(null)
    })
  })

  context('支付宝', () => {

    it('支付宝购买', () => {

      return requestToApiServer()
        .post(`/productorder/${product.id}`)
        .set({'x-jwt': jwt})
        .send({
          payType: 'aliPay'
        })
        .expect(200)
    })
  })
})
